#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

#define SIZE 256
#define NUM 16

void ReadDirect(char* cmd)
{
  char* ptr = cmd;
  int count = 0;
  while (*ptr){
    if(*ptr=='>'){
      ++count;
      *ptr = '\0';
      ++ptr;
      if (*ptr == '>'){
        ++count;
        *ptr++ = '\0';
      }
      // 跳过空格
      while (*ptr == ' '){
        ++ptr;
      }
      char* start = ptr;
      while (*ptr != '\0' && *ptr != ' '){
        ++ptr;
      }
      *ptr = '\0'; 
      // 重定向
      if (count == 1){
        int fd = open(start, O_CREAT|O_WRONLY, 0644);
        dup2(fd, 1);
      }
      else if (count == 2){
        // 追加重定向  
        int fd = open(start, O_CREAT|O_WRONLY|O_APPEND, 0644);
        dup2(fd, 1);
      }
    }
    else if (*ptr == '<'){
      // 输入重定向
      // 跳过空格
      *ptr++ = '\0';
      while (*ptr == ' '){
        ++ptr;
      }
      char* start = ptr;
      while (*ptr != '\0' && *ptr != ' '){
        ++ptr;
      }
      *ptr = '\0'; 
      // 重定向
      int fd = open(start, O_RDONLY);
      dup2(fd, 0);
    }
    else{
      ++ptr;
    }
  }
}

int main()
{
  char buf[SIZE];// 命令行缓冲区
  while (1){
    // 清空缓冲区
    buf[0] = '\0';
    const char* cmd_line = "[temp@VM-0-9-centos MyShell]#";
    printf("%s", cmd_line);
    fgets(buf, SIZE, stdin);
    buf[strlen(buf)-1] = '\0'; // 把buf最后一个字符'\n'置为'\0'
    
    pid_t id = fork();
    if (id < 0){
      // 进程创建失败
      perror("fork error");
      continue;
    }
    else if (id == 0){
      // child
      // 进程替换
      // 检测命令是否需要shell本身执行，例如cd
      
      ReadDirect(buf);
      // 命令行解析
      // strtok分割字符
      char* argc[NUM] = { NULL };
      argc[0] = strtok(buf, " ");
      int i = 0;
      for (i = 1; argc[i-1]; ++i){
        argc[i] = strtok(NULL, " ");
      }
  
      if (argc[0] != NULL && strcmp("cd", argc[0]) == 0){
        if (argc[1] != NULL)
          chdir(argc[1]);
      }
      execvp(argc[0], argc);
      exit(1);
    }

    // parent
    // 父进程通过阻塞等待方式读取子进程退出信息
    int status;
    pid_t ret = waitpid(id, &status, 0); 
    if (ret > 0){
      // 等待成功
      if (WIFEXITED(status)){
        // 子进程正常退出
        printf("exit code is: %d\n", WEXITSTATUS(status));
      }
      else{
        // 子进程异常退出
        printf("exit failed, exit singal is %d\n", WIFEXITED(status));
      }
    }
    else{
      printf("wait failed\n");
    }
  }

  
  return 0;
}
